import japa.parser.ASTHelper;
import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.ImportDeclaration;
import japa.parser.ast.PackageDeclaration;
import japa.parser.ast.body.BodyDeclaration;
import japa.parser.ast.body.ClassOrInterfaceDeclaration;
import japa.parser.ast.body.FieldDeclaration;
import japa.parser.ast.body.MethodDeclaration;
import japa.parser.ast.body.TypeDeclaration;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.visitor.VoidVisitorAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;


public class SamplesGenerator {

	ArrayList<TestCase> suiteSample;
	public static ClassOrInterfaceType superclass;
	static MethodDeclaration setUpMethod;
	static ArrayList<MethodDeclaration> testMethods = new ArrayList<MethodDeclaration>();

	public SamplesGenerator(String pathManual, String pathRandoop,
			float percentMan, int total) {
		this.suiteSample = new ArrayList<TestCase>();
		getManualSample(pathManual);


	}


	private void getManualSample(String pathManual) {
		File folder = new File (pathManual);
		File[] junitClasses = folder.listFiles();

		for (File file : junitClasses) {
			if (file.getName().endsWith(".java")){
				ArrayList<CompilationUnit> cUnits = getCompUnit(file);
				CompilationUnit cu = cUnits.get(0);
				ArrayList<JUnitClass> JUClasses = new ArrayList<JUnitClass>();
				JUClasses.add(recordingTestElements(cu));
			}
			
		}

	}


	private JUnitClass recordingTestElements(CompilationUnit cu) {
		JUnitClass jcClass;
		String name = cu.getTypes().get(0).getName();
		
		HashSet<ImportDeclaration> imports = new HashSet<ImportDeclaration>();
		imports.addAll(cu.getImports());
		
		HashSet<FieldDeclaration> fields = new HashSet<FieldDeclaration>();
		
		for (TypeDeclaration type : cu.getTypes()) {
			List<BodyDeclaration> members = type.getMembers();
			for (BodyDeclaration member : members) {
				if (member instanceof FieldDeclaration) {
					FieldDeclaration field = (FieldDeclaration) member;
					fields.add(field);
				}
			}
		}
		new MethodVisitor().visit(cu, null);
		if (setUpMethod != null)
			jcClass = new JUnitClass(name, imports, fields, setUpMethod.toString());
		else jcClass = new JUnitClass(name, imports, fields);
		new MethodVisitor2().visit(cu, null);
		
		return generateUnits(cu, jcClass, testMethods);
	}


	private JUnitClass generateUnits(CompilationUnit cu, JUnitClass jcClass, ArrayList<MethodDeclaration> testMethods) {
		CompilationUnit targetCompilationUnit = new CompilationUnit();;
		
		if (cu.getPackage() != null){
			NameExpr namePack = new NameExpr(cu.getPackage().getName().toString());
			targetCompilationUnit.setPackage(new PackageDeclaration(namePack));
		}
	
		ArrayList<ImportDeclaration> list = toList(jcClass.getImports());
		targetCompilationUnit.setImports(list);

		TypeDeclaration originalType = cu.getTypes().get(0);
		int mod = originalType.getModifiers();
		ArrayList<ClassOrInterfaceType> superclasses = new ArrayList<ClassOrInterfaceType>();
		superclasses.add(superclass);
		ClassOrInterfaceDeclaration type = new ClassOrInterfaceDeclaration(null, mod , null, false, jcClass.getName(), null, superclasses, null, null);
		
		ASTHelper.addTypeDeclaration(targetCompilationUnit, type);
		
		// Setting the class fields
		for (FieldDeclaration field : jcClass.getFields()) {
			ASTHelper.addMember(type, field);
		}

		// Setting the class the methods
//		for (MethodDeclaration setUpOrTearDown : setUpTearDownMethods) {
//			ASTHelper.addMember(type, setUpOrTearDown);
//		}

//		for (MethodDeclaration testMethod : testMethods) {
//			ASTHelper.addMember(type, testMethod);
//		}
		return null;
	}


	private ArrayList<ImportDeclaration> toList(
			HashSet<ImportDeclaration> imports) {
		ArrayList<ImportDeclaration> list = new ArrayList<ImportDeclaration>();
		
		Iterator<ImportDeclaration> it = imports.iterator();
		while(it.hasNext()){
			list.add(it.next());
		}
		return list;
	}


	private String importsToString(List<ImportDeclaration> imports) {
		String impStr = "";
		for (ImportDeclaration importDeclaration : imports) {
			impStr+=importDeclaration.toString()+'\n';
		}
		return impStr;
	}


	public ArrayList<CompilationUnit> getCompUnit(File file){
		ArrayList<CompilationUnit> cUnitsSource = new ArrayList<CompilationUnit>();
		FileInputStream in = null;
		System.out.println("file   "+file);

		if (file.getName().endsWith(".java")){
			try {
				in = new FileInputStream(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			try {
				// parse the file
				cUnitsSource.add (JavaParser.parse(in));
			} catch (ParseException e) {
				e.printStackTrace();
			} finally {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		}
		return cUnitsSource;
	}

	
	private static class MethodVisitor extends VoidVisitorAdapter {

        @Override
        public void visit(MethodDeclaration n, Object arg) {
            if (n.getName().equals("setUp")){
            	System.out.println(n.getName());
            	setUpMethod = n;
            }
        }
    }
	
	private static class MethodVisitor2 extends VoidVisitorAdapter {

        @Override
        public void visit(MethodDeclaration n, Object arg) {
            if (n.getName().equals("test")){
            	System.out.println(n.getName());
            	testMethods.add(n);
            }
        }
    }
	
	private static class ClassVisitor extends VoidVisitorAdapter {

		@Override
		public void visit(ClassOrInterfaceDeclaration n, Object o) {
			List<ClassOrInterfaceType> superclasses = n.getExtends();
			if (superclasses != null && superclasses.size() >0 )
				superclass = n.getExtends().get(0);
			else superclass = null;
		}
	}
}

